package interoperability
import nextgen.Interoperability;

import com.hp.hpl.jena.rdf.model.*
import com.hp.hpl.jena.query.*
import com.hp.hpl.jena.graph.*
import com.hp.hpl.jena.ontology.*


class ComputeFactsService {
	
    static transactional = true
	def canConnectTo= [] as Set
	def inputPayload= [:]
	def outputPayload= [:]
	def enterpriseModel= null
		
	def computeFacts() {
		// set up the initial model
		def serviceOnt= "http://localhost:8080/uploader/resources/wsdl20.rdf".toURL().openStream()
		def annotProps= "http://localhost:8080/uploader/resources/AnnotationProperties.owl".toURL().openStream()
		def serviceOntProps= "http://localhost:8080/uploader/resources/ServiceOntologyProperties.owl".toURL().openStream()
		def provisions= "http://localhost:8081/Provision/nextgen/rdf/nt".toURL().openStream()
		def model= ModelFactory.createDefaultModel()
		def rdfXmlReader= model.getReader("RDF/XML")
		def nTripleReader= model.getReader("N-TRIPLE")
		rdfXmlReader.read(model, serviceOnt, "http://www.w3.org/ns/wsdl-rdf")
		rdfXmlReader.read(model, annotProps, "http://www.jpdo.gov/nextgen/annotations")
		rdfXmlReader.read(model, serviceOntProps, "http://www.jpdo.gov/nextgen/ServiceOntologyProperties")
		nTripleReader.read(model, provisions, "http://www.jpdo.gov/nextgen/provisions")

		// get a list of the services
		def catalog= "http://localhost:8084/Catalog/nextgen".toURL().openStream()
		def webservices= new XmlSlurper().parse(catalog)
		// for each service, get the rdf and add to model
		webservices.webService.each { service ->
			def wsOnt= "http://localhost:8084/Catalog/nextgen/rdf/nt?url=${service.url}".toURL().openStream()
			nTripleReader.read(model, wsOnt, "http://www.jpdo.gov/nextgen/${service.name.toString().replaceAll(' ', '')}")
		}
		
		// populate the opGraph map
		def opQuery= """
			PREFIX wsdl-rdf: <http://www.w3.org/ns/wsdl-rdf#>
			PREFIX jpdo: <http://www.jpdo.gov/nextgen#>
			SELECT ?operation ?inputGraph ?outputGraph
			WHERE { ?operation wsdl-rdf:interfaceMessageReference ?input .
					?input a wsdl-rdf:InputMessage .
					OPTIONAL { ?input jpdo:payload ?inputGraph } .
					?operation wsdl-rdf:interfaceMessageReference ?output .
					?output a wsdl-rdf:OutputMessage .
					OPTIONAL { ?output jpdo:payload ?outputGraph }
				  }
		"""
		def results= runQuery(opQuery, model)
		results.each { fact ->
			def opr= fact[0]
			def inp= fact[1]
			def out= fact[2]
			if (inp) { inputPayload[opr]= inp }
			if (out) { outputPayload[opr]= out }
		}
		this.enterpriseModel= ModelFactory.createOntologyModel(OntModelSpec.OWL_DL_MEM_RULE_INF)
		def entRdfXmlReader= model.getReader("RDF/XML")
		def enterpriseOntology= "http://localhost:8080/uploader/resources/SampleEnterpriseOntology.owl".toURL().openStream()
		entRdfXmlReader.read(this.enterpriseModel, enterpriseOntology, "http://www.jpdo.gov/nextgen/SampleEnterpriseOntology")
		// for every operation with an output payload, o
		outputPayload.keySet().each { o ->
			// get the 'output' payload for o
			def opay= outputPayload[o]
			// for each operation with an input payload, i
			inputPayload.keySet().each { i ->
				// get the 'input' payload for Y
				def ipay= inputPayload[i]
				compareModel(i, o, ipay, opay)
			}
		}
		updateFacts()
    }
		
	def compareModel(input, output, inputPayload, outputPayload) {
		// make an ask out of the inputPayload
		def ask= QueryFactory.create(inputPayload.toString().replaceAll('GRAPH', 'ASK').replaceAll('_:', '?'))
		// make a construct out of the outputPayload
		def con= QueryFactory.create(outputPayload.toString().replaceAll('GRAPH', 'CONSTRUCT') + '\nWHERE {}')
		// create an empty model and add the construct query result
		def model= ModelFactory.createDefaultModel()
		def g1= QueryExecutionFactory.create(con, model).execConstruct()
		// add the constructed graph to the enterprise model to test for a connection
		this.enterpriseModel.addSubModel(g1)
		// query the model w/ the ask query
		def result= QueryExecutionFactory.create(ask, this.enterpriseModel).execAsk()
		// add successes to canConnectTo in n-triples form
		if ( result )
		{
			canConnectTo << "${output} <http://www.jpdo.gov/nextgen#canConnectTo> ${input} .\n"
		}
		// remove the constructed graph from the enterprise model
		this.enterpriseModel.removeSubModel(g1)
    }
	
	
    def updateFacts() { 
		if (canConnectTo != []) {
			// blank the current InteropFacts extent
			Interoperability.list().each { it.delete() }
			// add each result as an InteropFact
			canConnectTo.each { fact ->
				def x= fact.tokenize(' ')[0].toString()
				def y= fact.tokenize(' ')[2].toString()
				def interopFact= new Interoperability()
				interopFact.fromUrl= x
				interopFact.toUrl= y
				interopFact.save()
			}
		}
		// else, print an error message
		else { println 'error during interoperability update.  no facts added or deleted' }
    }
	
	def runQuery(String query, model) {
		def results= [] as Set
		def qPlan= QueryFactory.create(query)
		def execution= QueryExecutionFactory.create(qPlan, model)
		try {
			def resultSet= execution.execSelect()
			def variables= resultSet.getResultVars()
			for ( ; resultSet.hasNext() ; ) {
				def solution= resultSet.next()
				def result= []
				variables.each { var ->
					result << solution.get(var)
				}
				results << result
			}
			
		}
		finally { 
			execution.close()
			return results 
		}
	}
}
